#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import division
from math import exp
try:
    import json
except ImportError:
    import simplejson as json
import time
import urllib
import urllib2
import logging
from Queue import Queue
from threading import Thread
import threading
import numpy as np
def sigmoid(inX):#判定公式
    rlist = []
    for x in inX:
        rlist.append(1.0/(1+exp(-x)))
    return np.array(rlist).transpose()

def sig(inx,theta):
    b = np.dot(inx,theta)
    return b

def gtadAscent(dataMatIn,classLabels,k):#梯度下降优化参数
    dataMatrix = np.array(dataMatIn)
    labelMat = np.array(classLabels).transpose()
    m,n = np.shape(dataMatrix)
    alpha = 0.001
    maxCycles = k
    weights = np.ones((n,))
    for x in range (maxCycles):
        h = sigmoid(np.dot(dataMatrix,weights))
        error = (labelMat - h)
        weights = weights + alpha*np.dot(dataMatrix.transpose(),error)
        print weights
    return weights
def _obj_hook(pairs):
    '''
    convert json object to python object.
    '''
    o = JsonObject()
    for k, v in pairs.iteritems():
        o[str(k)] = v
    return o

class APIError(StandardError):
    '''
    raise APIError if got failed json message.
    '''
    def __init__(self, error_code, error, request):
        self.error_code = error_code
        self.error = error
        self.request = request
        StandardError.__init__(self, error)

    def __str__(self):
        return 'APIError: %s: %s, request: %s' % (self.error_code, self.error, self.request)

class JsonObject(dict):
    '''
    general json object that can bind any fields but also act as a dict.
    '''
    def __getattr__(self, attr):
        return self[attr]

    def __setattr__(self, attr, value):
        self[attr] = value

def _encode_params(**kw):
    '''
    Encode parameters.
    '''
    args = []
    for k, v in kw.iteritems():
        qv = v.encode('utf-8') if isinstance(v, unicode) else str(v)
        args.append('%s=%s' % (k, urllib.quote(qv)))
    return '&'.join(args)

def _encode_multipart(**kw):
    '''
    Build a multipart/form-data body with generated random boundary.
    '''
    boundary = '----------%s' % hex(int(time.time() * 1000))
    data = []
    for k, v in kw.iteritems():
        data.append('--%s' % boundary)
        if hasattr(v, 'read'):
            # file-like object:
            ext = ''
            filename = getattr(v, 'name', '')
            n = filename.rfind('.')
            if n != (-1):
                ext = filename[n:].lower()
            content = v.read()
            data.append('Content-Disposition: form-data  name="%s"  filename="hidden"' % k)
            data.append('Content-Length: %d' % len(content))
            data.append('Content-Type: %s\r\n' % _guess_content_type(ext))
            data.append(content)
        else:
            data.append('Content-Disposition: form-data  name="%s"\r\n' % k)
            data.append(v.encode('utf-8') if isinstance(v, unicode) else v)
    data.append('--%s--\r\n' % boundary)
    return '\r\n'.join(data), boundary

_CONTENT_TYPES = { '.png': 'image/png', '.gif': 'image/gif', '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.jpe': 'image/jpeg' }

def _guess_content_type(ext):
    return _CONTENT_TYPES.get(ext, 'application/octet-stream')

_HTTP_GET = 0
_HTTP_POST = 1
_HTTP_UPLOAD = 2

def _http_get(url, authorization=None, **kw):
    logging.info('GET %s' % url)
    return _http_call(url, _HTTP_GET, authorization, **kw)

def _http_post(url, authorization=None, **kw):
    logging.info('POST %s' % url)
    return _http_call(url, _HTTP_POST, authorization, **kw)

def _http_upload(url, authorization=None, **kw):
    logging.info('MULTIPART POST %s' % url)
    return _http_call(url, _HTTP_UPLOAD, authorization, **kw)

def _http_call(url, method, authorization, **kw):
    '''
    send an http request and expect to return a json object if no error.
    '''
    params = None
    boundary = None
    if method==_HTTP_UPLOAD:
        params, boundary = _encode_multipart(**kw)
    else:
        params = _encode_params(**kw)
    http_url = '%s?%s' % (url, params) if method==_HTTP_GET else url
    http_body = None if method==_HTTP_GET else params
    req = urllib2.Request(http_url, data=http_body)
    if authorization:
        req.add_header('Authorization', 'OAuth2 %s' % authorization)
    if boundary:
        req.add_header('Content-Type', 'multipart/form-data  boundary=%s' % boundary)
    resp = ''
    fails = 0
    while True:
        try:
            if fails > 2:
                break
            resp = urllib2.urlopen(req, timeout=9)
        except urllib2.URLError, e: 
            fails += 1
            logging.error('Error:%s when url:%s fails:%s' % (e, http_url, fails))
            time.sleep(9)
        else:
            break
    body = resp.read()
    r = json.loads(body, object_hook=_obj_hook)
    if hasattr(r, 'error_code'):
        raise APIError(r.error_code, getattr(r, 'error', ''), getattr(r, 'request', ''))
    return r

class HttpObject(object):

    def __init__(self, client, method):
        self.client = client
        self.method = method

    def __getattr__(self, attr):
        def wrap(**kw):
            if self.client.is_expires():
                raise APIError('21327', 'expired_token', attr)
            return _http_call('%s%s.json' % (self.client.api_url, attr.replace('__', '/')), self.method, self.client.access_token, **kw)
        return wrap

class APIClient(object):
    '''
    API client using synchronized invocation.
    '''
    def __init__(self, app_key, app_secret, redirect_uri=None, response_type='code', domain='api.weibo.com', version='2'):
        self.client_id = app_key
        self.client_secret = app_secret
        self.redirect_uri = redirect_uri
        self.response_type = response_type
        self.auth_url = 'https://%s/oauth2/' % domain
        self.api_url = 'https://%s/%s/' % (domain, version)
        self.access_token = None
        self.expires = 0.0
        self.get = HttpObject(self, _HTTP_GET)
        self.post = HttpObject(self, _HTTP_POST)
        self.upload = HttpObject(self, _HTTP_UPLOAD)

    def set_access_token(self, access_token, expires_in):
        self.access_token = str(access_token)
        self.expires = float(expires_in)

    def get_authorize_url(self, redirect_uri=None, display='default'):
        '''
        return the authroize url that should be redirect.
        '''
        redirect = redirect_uri if redirect_uri else self.redirect_uri
        if not redirect:
            raise APIError('21305', 'Parameter absent: redirect_uri', 'OAuth2 request')
        return '%s%s?%s' % (self.auth_url, 'authorize', \
                _encode_params(client_id = self.client_id, \
                        response_type = 'code', \
                        display = display, \
                        redirect_uri = redirect))

    def request_access_token(self, code, redirect_uri=None, uname='', upassword=''):
        '''
        return access token as object: {"access_token":"your-access-token","expires_in":12345678}, expires_in is standard unix-epoch-time
        '''
        redirect = redirect_uri if redirect_uri else self.redirect_uri
        g_type = 'authorization_code'
        if not redirect:
            g_type = 'password'
        r = _http_post('%s%s' % (self.auth_url, 'access_token'), \
                client_id = self.client_id, \
                client_secret = self.client_secret, \
                username = uname, password = upassword, \
                code = code, grant_type = g_type)
        r.expires_in += int(time.time())
        return r

    def is_expires(self):
        return not self.access_token or time.time() > self.expires

    def __getattr__(self, attr):
        return getattr(self.get, attr)
def get_feature_new(client,Uid):#获取对应uid用户所发微博信息
    Original = set()
    reList = []
    user = client.get.users__show(uid = Uid)
    pic = 0
    comments = 0
    i = 0#记录微博数量
    Ostatuses = client.get.statuses__timeline_batch(screen_names = user.screen_name,count = 50).statuses
    for x in Ostatuses:
        i = i + 1
        try:
            comments = comments + x.comments_count
            repost_id = x.retweeted_status.idstr
            if x.retweeted_status.pic_urls != []:
                pic = pic + 1
            reList.append(repost_id)
            Original.add(repost_id)
        except:
            pass
    m = 0#记录重复转发微博次数
    for y in Original:
        m = m + reList.count(y)
    C_to_O = comments/i#所发微博被评论总数和微博数比值
    R_to_A = len(reList)/i#转发微博占总微博比值
    P_to_R = pic/(len(reList)+1)#转发微博中带图微博比值
    R_to_O = m/len(Original) - 1#转发微博重复率
    followers = user.followers_count
    friends = user.friends_count
    statuses = user.statuses_count
    S_to_F = statuses/followers
    S_to_F = S_to_F/10
    F_to_F = followers/friends
    F_to_F = F_to_F/10
    return [1,R_to_A,R_to_O,P_to_R,C_to_O]
def get_feature(client,Uid):
    Original = set()
    All = set()
    user = client.get.users__show(uid = Uid)
    O_to_A = 0.0
    Ostatuses = client.get.statuses__user_timeline__ids(screen_name = user.screen_name,feature = 1,count = 100).statuses
    Astatuses = client.get.statuses__user_timeline__ids(screen_name = user.screen_name,feature = 0,count = 100).statuses
    for x in Ostatuses:
        Original.add(x)
    for x in Astatuses:
        All.add(x)
    R_to_A = (len(Original&All)-3)/100#原创微博所占比
    followers = user.followers_count
    friends = user.friends_count
    statuses = user.statuses_count
    S_to_F = statuses/followers
    S_to_F = S_to_F/10
    F_to_F = followers/friends#粉丝和关注数的比值
    F_to_F = F_to_F/10
    return [1,R_to_A,F_to_F,S_to_F]
def run_navy(client,Uids):
    global navy_info
    while True:
        time.sleep(0.1)
        if Uids.empty():
            print '队列中已无对象'
            return navy_info
        uid = Uids.get()
        try:
            m = get_feature_new(client,uid)#获取对应uid信息
            navy_info.append(m)            
            print str(m) +':-' +str(uid)
        except:
            #Uids.put(uid)
            pass
def run_normal(client,Uids):
    global normal_info
    while True:
        time.sleep(0.1)
        if Uids.empty():
            print '队列中已无对象'
            return normal_info
        uid = Uids.get()
        try:
            m = get_feature_new(client,uid)#获取对应uid信息
            normal_info.append(m)
            print str(m) +':-' +str(uid)
        except:
            #Uids.put(uid)
            pass
try:
    #step 1 定义 app key，app secret， user name, user password：

    APP_KEY = "2323547071"
    APP_SECRET = "16ed80cc77fea11f7f7e96eca178ada3"

    USER_NAME = "18610491651"  #授权用户名
    USER_PASSWD = "zsdc12"  #授权用户密码

    #step 2 获取OAuth2.0 Access Token:
    client = APIClient(app_key=APP_KEY, app_secret=APP_SECRET)
    r = client.request_access_token(0, None, USER_NAME, USER_PASSWD)
    client.set_access_token(r.access_token, r.expires_in)
    #step 3 使用获得的OAuth2.0 Access Token调用API
    # print client.get.account__get_uid()
    print r
    print "本时段剩余访问次数：", client.get.account__rate_limit_status().remaining_ip_hits
    f = open('Navy003.txt','r')
    Navy_list = f.readlines()
    f.close()
    queue_navy = Queue()
    navy_info = []
    for x in Navy_list:
        x = x.split('\n')[0]
        queue_navy.put(long(x))
    thlist = []
    for i in range(0,19):
        thlist.append(threading.Thread(target = run_navy,args = (client,queue_navy)))
    for x in thlist:
        x.start()
    for x in thlist:
        x.join()
    print"水军信息初始化完毕"#获取各个水军微博信息
    f = open('Normal001.txt','r')
    normal_list = f.readlines()
    f.close()
    queue_normal = Queue()
    normal_info = []
    for x in normal_list:
        x = x.split('\n')[0]
        queue_normal.put(long(x))
    thlist = []
    for i in range(0,19):
        thlist.append(threading.Thread(target = run_normal,args = (client,queue_normal)))
    for x in thlist:
        x.start()#获取普通用户微博信息
    for x in thlist:
        x.join()
    result_x = []
    result_y = []
    dellist = []
    print 1
    for x in navy_info:
        if x[2] > 10 or x[4] > 0.7:
            print x
            dellist.append(x)
    print 2
    for k in dellist:
        navy_info.remove(k)
    print 3
    dellist = []
    for x in normal_info:
        if x[2] > 10:
            dellist.append(x)#将变量过大的信息加入删除列表中
    print 4
    for z in dellist:
        normal_info.remove(z)#删除无用信息
    print 5
    for y in navy_info:
        result_x.append(y)
        result_y.append(0)
    print 6
    for y in normal_info:
        result_x.append(y)
        result_y.append(1)
    print '开始计算'
    #weights = gtadAscent(result_x,result_y,1000)#计算各变量对应系数
except Exception as pyOauth2Error:
        print pyOauth2Error
